--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Node / ReticulumProjects / MeshChatX.git / files / meshchatx / src / backend / http / routes / database.py
Displaying Raw • Download
meshchatx/src/backend/http/routes/database.py 4bd787ccd70a459a02eececca3f942f0e64ec4ce (4bd787cc) Text, 15.60 KB
T8b949e# SPDX-License-Identifier: 0BSD
T8b949e"""HTTP routes: database."""
Tff7b72from T7ee787__future__ Tff7b72import Te6edf3annotations
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787httpT7ee787.T7ee787meshchat_names Tff7b72import Tb4b4b4( T8b949e# noqa: F401
Te6edf3GeoValidationErrorTb4b4b4,
Te6edf3OutboundHttpBlockedErrorTb4b4b4,
Te6edf3OverlayExportErrorTb4b4b4,
Te6edf3OverlaySourceParseErrorTb4b4b4,
Te6edf3PluginSecurityErrorTb4b4b4,
Te6edf3AsyncUtilsTb4b4b4,
Te6edf3InterfaceConfigParserTb4b4b4,
Te6edf3InterfaceDiscoveryTb4b4b4,
Te6edf3InterfaceEditorTb4b4b4,
Te6edf3LOGIN_PATHTb4b4b4,
Te6edf3LXMFTb4b4b4,
Te6edf3LxmfAudioFieldTb4b4b4,
Te6edf3LxmfFileAttachmentTb4b4b4,
Te6edf3LxmfFileAttachmentsFieldTb4b4b4,
Te6edf3LxmfImageFieldTb4b4b4,
Te6edf3MAX_EXPORT_TILESTb4b4b4,
Te6edf3MarkdownRendererTb4b4b4,
Te6edf3NomadnetFileDownloaderTb4b4b4,
Te6edf3NomadnetPageDownloaderTb4b4b4,
Te6edf3RNProbeHandlerTb4b4b4,
Te6edf3RNSTb4b4b4,
Te6edf3ReticulumMeshChatTb4b4b4,
Te6edf3SETUP_PATHTb4b4b4,
Te6edf3TRANSPARENT_TILETb4b4b4,
Te6edf3TelemeterTb4b4b4,
Te6edf3UTCTb4b4b4,
Te6edf3WSMsgTypeTb4b4b4,
Te6edf3_is_chaquopy_androidTb4b4b4,
Te6edf3_is_loopback_bind_hostTb4b4b4,
Te6edf3_request_client_ipTb4b4b4,
Te6edf3aiohttpTb4b4b4,
Te6edf3app_versionTb4b4b4,
Te6edf3assert_migration_context_pathsTb4b4b4,
Te6edf3asyncioTb4b4b4,
Te6edf3base64Tb4b4b4,
Te6edf3bcryptTb4b4b4,
Te6edf3binasciiTb4b4b4,
Te6edf3build_blocklist_export_documentTb4b4b4,
Te6edf3build_export_documentTb4b4b4,
Te6edf3build_messages_export_bundleTb4b4b4,
Te6edf3cache_statsTb4b4b4,
Te6edf3cancel_inbound_deliveriesTb4b4b4,
Te6edf3castTb4b4b4,
Te6edf3compute_lxmf_conversation_unread_from_latest_rowTb4b4b4,
Te6edf3configparserTb4b4b4,
Te6edf3contextlibTb4b4b4,
Te6edf3convert_db_favourite_to_dictTb4b4b4,
Te6edf3convert_db_lxmf_message_to_dictTb4b4b4,
Te6edf3convert_lxmf_message_to_dictTb4b4b4,
Te6edf3convert_nomadnet_field_data_to_mapTb4b4b4,
Te6edf3convert_nomadnet_string_data_to_mapTb4b4b4,
Te6edf3convert_propagation_node_state_to_stringTb4b4b4,
Te6edf3copyTb4b4b4,
Te6edf3datetimeTb4b4b4,
Te6edf3describe_port_conflictTb4b4b4,
Te6edf3detect_image_format_from_magicTb4b4b4,
Te6edf3ensure_outbound_http_allowedTb4b4b4,
Te6edf3ensure_session_csrf_tokenTb4b4b4,
Te6edf3filter_announced_dicts_by_search_queryTb4b4b4,
Te6edf3fresh_storage_at_targetTb4b4b4,
Te6edf3get_cached_active_linkTb4b4b4,
Te6edf3get_file_pathTb4b4b4,
Te6edf3get_sessionTb4b4b4,
Te6edf3get_trusted_proxy_cidrsTb4b4b4,
Te6edf3gif_utilsTb4b4b4,
Te6edf3i2p_supportTb4b4b4,
Te6edf3import_messages_export_bundleTb4b4b4,
Te6edf3ioTb4b4b4,
Te6edf3is_mbtiles_filenameTb4b4b4,
Te6edf3is_path_within_dirTb4b4b4,
Te6edf3is_port_in_useTb4b4b4,
Te6edf3is_user_facing_lxmf_payloadTb4b4b4,
Te6edf3jsonTb4b4b4,
Te6edf3list_host_network_interfacesTb4b4b4,
Te6edf3list_inbound_deliveriesTb4b4b4,
Te6edf3list_portsTb4b4b4,
Te6edf3load_app_security_settingsTb4b4b4,
Te6edf3loggerTb4b4b4,
Te6edf3loggingTb4b4b4,
Te6edf3lxmf_sidebar_preview_for_conversation_latest_rowTb4b4b4,
Te6edf3memory_log_handlerTb4b4b4,
Te6edf3message_fields_have_attachmentsTb4b4b4,
Te6edf3migrate_legacy_to_targetTb4b4b4,
Te6edf3mime_for_image_typeTb4b4b4,
Te6edf3normalize_identity_storage_hashTb4b4b4,
Te6edf3normalize_lxmf_sieve_filtersTb4b4b4,
Te6edf3normalize_message_blocklistTb4b4b4,
Te6edf3osTb4b4b4,
Te6edf3parse_bool_query_paramTb4b4b4,
Te6edf3parse_import_documentTb4b4b4,
Te6edf3parse_lxmf_display_nameTb4b4b4,
Te6edf3parse_lxmf_propagation_node_app_dataTb4b4b4,
Te6edf3parse_lxmf_sieve_filters_jsonTb4b4b4,
Te6edf3parse_lxmf_stamp_costTb4b4b4,
Te6edf3parse_message_blocklist_jsonTb4b4b4,
Te6edf3parse_nomadnetwork_node_display_nameTb4b4b4,
Te6edf3platformTb4b4b4,
Te6edf3privacy_mode_enabledTb4b4b4,
Te6edf3psutilTb4b4b4,
Te6edf3purge_messages_before_cutoffTb4b4b4,
Te6edf3reTb4b4b4,
Te6edf3resolve_message_age_cutoffTb4b4b4,
Te6edf3reticulum_pathfindingTb4b4b4,
Te6edf3rotate_session_csrf_tokenTb4b4b4,
Te6edf3rrc_protocolTb4b4b4,
Te6edf3safe_path_under_dirTb4b4b4,
Te6edf3sanitize_sticker_emojiTb4b4b4,
Te6edf3sanitize_sticker_nameTb4b4b4,
Te6edf3sanitize_websocket_config_updateTb4b4b4,
Te6edf3save_app_security_settingsTb4b4b4,
Te6edf3secretsTb4b4b4,
Te6edf3shutilTb4b4b4,
Te6edf3sqlite3Tb4b4b4,
Te6edf3sticker_pack_utilsTb4b4b4,
Te6edf3sysTb4b4b4,
Te6edf3tempfileTb4b4b4,
Te6edf3threadingTb4b4b4,
Te6edf3timeTb4b4b4,
Te6edf3tracebackTb4b4b4,
Te6edf3user_agent_hashTb4b4b4,
Te6edf3validate_export_documentTb4b4b4,
Te6edf3webTb4b4b4,
Te6edf3websocket_type_requires_authTb4b4b4,
Te6edf3zipfileTb4b4b4,
Tb4b4b4)
Tff7b72def Td2a8ffregister_database_routesTb4b4b4(Te6edf3routesTb4b4b4, Te6edf3appTb4b4b4)Tb4b4b4:
T8b949e# ── Database ─────────────────────────────────────────────────────
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/database/snapshotTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffcreate_db_snapshotTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3data Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffjsonTb4b4b4(Tb4b4b4)
Te6edf3name Tff7b72= Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4, Ta5d6fffTa5d6ff"Ta5d6ffsnapshot-Tffd700{Tffa657intTb4b4b4(Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4)
Te6edf3result Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffcreate_snapshotTb4b4b4(Te6edf3appTff7b72.Td2a8ffstorage_pathTb4b4b4, Te6edf3nameTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffsuccessTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffresultTa5d6ff"Tb4b4b4: Te6edf3resultTb4b4b4}Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/database/snapshotsTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fflist_db_snapshotsTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3limit Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflimitTa5d6ff"Tb4b4b4, T79c0ff100Tb4b4b4)Tb4b4b4)
Te6edf3offset Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffoffsetTa5d6ff"Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4)
Te6edf3snapshots Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8fflist_snapshotsTb4b4b4(Te6edf3appTff7b72.Td2a8ffstorage_pathTb4b4b4)
Te6edf3total Tff7b72= Tffa657lenTb4b4b4(Te6edf3snapshotsTb4b4b4)
Te6edf3paginated_snapshots Tff7b72= Te6edf3snapshotsTb4b4b4[Te6edf3offset Tb4b4b4: Te6edf3offset Tff7b72+ Te6edf3limitTb4b4b4]
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffsnapshotsTa5d6ff"Tb4b4b4: Te6edf3paginated_snapshotsTb4b4b4,
Ta5d6ff"Ta5d6fftotalTa5d6ff"Tb4b4b4: Te6edf3totalTb4b4b4,
Ta5d6ff"Ta5d6fflimitTa5d6ff"Tb4b4b4: Te6edf3limitTb4b4b4,
Ta5d6ff"Ta5d6ffoffsetTa5d6ff"Tb4b4b4: Te6edf3offsetTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
Tf0883e@routesTff7b72.Td2a8ffdeleteTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/database/snapshots/Tffd700{filename}Ta5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffdelete_db_snapshotTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3filename Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3filenameTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff.zipTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3filename Tff7b72+Tff7b72= Ta5d6ff"Ta5d6ff.zipTa5d6ff"
Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffdelete_snapshot_or_backupTb4b4b4(
Te6edf3appTff7b72.Td2a8ffstorage_pathTb4b4b4,
Te6edf3filenameTb4b4b4,
Te6edf3is_backupTff7b72=Tff7b72FalseTb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffsuccessTa5d6ff"Tb4b4b4}Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/database/restoreTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffrestore_db_snapshotTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3content_type Tff7b72= Te6edf3requestTff7b72.Td2a8ffheadersTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffContent-TypeTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)
T8b949e# multipart upload: restore from a user-provided backup/zip file
Tff7b72if Ta5d6ff"Ta5d6ffmultipart/form-dataTa5d6ff" Tff7b72in Te6edf3content_typeTb4b4b4:
Te6edf3reader Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffmultipartTb4b4b4(Tb4b4b4)
Te6edf3field Tff7b72= Tff7b72await Te6edf3readerTff7b72.Td2a8ffnextTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3field Tff7b72is Tff7b72None Tff7b72or Te6edf3fieldTff7b72.Td2a8ffname Tff7b72!= Ta5d6ff"Ta5d6fffileTa5d6ff"Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffRestore file is requiredTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
Tff7b72with Te6edf3tempfileTff7b72.Td2a8ffNamedTemporaryFileTb4b4b4(Te6edf3deleteTff7b72=Tff7b72FalseTb4b4b4) Tff7b72as Te6edf3tmpTb4b4b4:
Tff7b72while Tff7b72TrueTb4b4b4:
Te6edf3chunk Tff7b72= Tff7b72await Te6edf3fieldTff7b72.Td2a8ffread_chunkTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3chunkTb4b4b4:
Tff7b72break
Te6edf3tmpTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3chunkTb4b4b4)
Te6edf3temp_path Tff7b72= Te6edf3tmpTff7b72.Td2a8ffname
Tff7b72tryTb4b4b4:
Te6edf3result Tff7b72= Te6edf3appTff7b72.Td2a8ffrestore_databaseTb4b4b4(Te6edf3temp_pathTb4b4b4, Te6edf3relaunchTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72finallyTb4b4b4:
Tff7b72with Te6edf3contextlibTff7b72.Td2a8ffsuppressTb4b4b4(Tf85149OSErrorTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3temp_pathTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffsuccessTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffresultTa5d6ff"Tb4b4b4: Te6edf3resultTb4b4b4,
Ta5d6ff"Ta5d6ffdatabaseTa5d6ff"Tb4b4b4: Te6edf3resultTb4b4b4,
Ta5d6ff"Ta5d6ffrequires_relaunchTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffDatabase restored. Application will restart.Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
T8b949e# JSON body: restore from an on-disk snapshot/auto-backup path
Te6edf3data Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffjsonTb4b4b4(Tb4b4b4)
Te6edf3path Tff7b72= Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3pathTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffNo path providedTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
Te6edf3resolved Tff7b72= Te6edf3appTff7b72.Td2a8ff_resolve_database_restore_pathTb4b4b4(Te6edf3pathTb4b4b4)
Tff7b72if Tff7b72not Te6edf3resolvedTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffSnapshot not foundTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff404Tb4b4b4,
Tb4b4b4)
Te6edf3result Tff7b72= Te6edf3appTff7b72.Td2a8ffrestore_databaseTb4b4b4(Te6edf3resolvedTb4b4b4, Te6edf3relaunchTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffsuccessTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffresultTa5d6ff"Tb4b4b4: Te6edf3resultTb4b4b4,
Ta5d6ff"Ta5d6ffrequires_relaunchTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffDatabase restored. Application will restart.Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/database/backupsTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8fflist_db_backupsTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3limit Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflimitTa5d6ff"Tb4b4b4, T79c0ff100Tb4b4b4)Tb4b4b4)
Te6edf3offset Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffoffsetTa5d6ff"Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4)
Te6edf3backup_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3appTff7b72.Td2a8ffstorage_pathTb4b4b4, Ta5d6ff"Ta5d6ffdatabase-backupsTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3backup_dirTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffbackupsTa5d6ff"Tb4b4b4: Tb4b4b4[Tb4b4b4]Tb4b4b4, Ta5d6ff"Ta5d6fftotalTa5d6ff"Tb4b4b4: T79c0ff0Tb4b4b4, Ta5d6ff"Ta5d6fflimitTa5d6ff"Tb4b4b4: Te6edf3limitTb4b4b4, Ta5d6ff"Ta5d6ffoffsetTa5d6ff"Tb4b4b4: Te6edf3offsetTb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3backups Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3file Tff7b72in Te6edf3osTff7b72.Td2a8fflistdirTb4b4b4(Te6edf3backup_dirTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3fileTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff.zipTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3full_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3backup_dirTb4b4b4, Te6edf3fileTb4b4b4)
Te6edf3stats Tff7b72= Te6edf3osTff7b72.Td2a8ffstatTb4b4b4(Te6edf3full_pathTb4b4b4)
Te6edf3backupsTff7b72.Td2a8ffappendTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Te6edf3fileTb4b4b4,
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Te6edf3full_pathTb4b4b4,
Ta5d6ff"Ta5d6ffsizeTa5d6ff"Tb4b4b4: Te6edf3statsTff7b72.Td2a8ffst_sizeTb4b4b4,
Ta5d6ff"Ta5d6ffcreated_atTa5d6ff"Tb4b4b4: Te6edf3datetimeTff7b72.Td2a8fffromtimestampTb4b4b4(
Te6edf3statsTff7b72.Td2a8ffst_mtimeTb4b4b4,
Te6edf3UTCTb4b4b4,
Tb4b4b4)Tff7b72.Td2a8ffisoformatTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3sorted_backups Tff7b72= Tffa657sortedTb4b4b4(
Te6edf3backupsTb4b4b4,
Te6edf3keyTff7b72=Tff7b72lambda Te6edf3xTb4b4b4: Te6edf3xTb4b4b4[Ta5d6ff"Ta5d6ffcreated_atTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3reverseTff7b72=Tff7b72TrueTb4b4b4,
Tb4b4b4)
Te6edf3total Tff7b72= Tffa657lenTb4b4b4(Te6edf3sorted_backupsTb4b4b4)
Te6edf3paginated_backups Tff7b72= Te6edf3sorted_backupsTb4b4b4[Te6edf3offset Tb4b4b4: Te6edf3offset Tff7b72+ Te6edf3limitTb4b4b4]
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffbackupsTa5d6ff"Tb4b4b4: Te6edf3paginated_backupsTb4b4b4,
Ta5d6ff"Ta5d6fftotalTa5d6ff"Tb4b4b4: Te6edf3totalTb4b4b4,
Ta5d6ff"Ta5d6fflimitTa5d6ff"Tb4b4b4: Te6edf3limitTb4b4b4,
Ta5d6ff"Ta5d6ffoffsetTa5d6ff"Tb4b4b4: Te6edf3offsetTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
Tf0883e@routesTff7b72.Td2a8ffdeleteTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/database/backups/Tffd700{filename}Ta5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffdelete_db_backupTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3filename Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3filenameTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff.zipTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3filename Tff7b72+Tff7b72= Ta5d6ff"Ta5d6ff.zipTa5d6ff"
Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffdelete_snapshot_or_backupTb4b4b4(
Te6edf3appTff7b72.Td2a8ffstorage_pathTb4b4b4,
Te6edf3filenameTb4b4b4,
Te6edf3is_backupTff7b72=Tff7b72TrueTb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffsuccessTa5d6ff"Tb4b4b4}Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/database/backups/Tffd700{filename}Ta5d6ff/downloadTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffdownload_db_backupTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3filename Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3filenameTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff.zipTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3filename Tff7b72+Tff7b72= Ta5d6ff"Ta5d6ff.zipTa5d6ff"
Te6edf3backup_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3appTff7b72.Td2a8ffstorage_pathTb4b4b4, Ta5d6ff"Ta5d6ffdatabase-backupsTa5d6ff"Tb4b4b4)
Te6edf3full_path Tff7b72= Te6edf3safe_path_under_dirTb4b4b4(Te6edf3backup_dirTb4b4b4, Te6edf3filenameTb4b4b4)
Tff7b72if Tff7b72not Te6edf3full_path Tff7b72or Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3full_pathTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffBackup not foundTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff404Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffFileResponseTb4b4b4(
Te6edf3pathTff7b72=Te6edf3full_pathTb4b4b4,
Te6edf3headersTff7b72=Tb4b4b4{
Ta5d6ff"Ta5d6ffContent-DispositionTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff'Ta5d6ffattachment; filename=Ta5d6ff"Tffd700{Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffbasenameTb4b4b4(Te6edf3full_pathTb4b4b4)Tffd700}Ta5d6ff"Ta5d6ff'Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/database/snapshots/Tffd700{filename}Ta5d6ff/downloadTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffdownload_db_snapshotTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3filename Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fffilenameTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3filenameTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff.zipTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3filename Tff7b72+Tff7b72= Ta5d6ff"Ta5d6ff.zipTa5d6ff"
Te6edf3snapshot_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3appTff7b72.Td2a8ffstorage_pathTb4b4b4, Ta5d6ff"Ta5d6ffsnapshotsTa5d6ff"Tb4b4b4)
Te6edf3full_path Tff7b72= Te6edf3safe_path_under_dirTb4b4b4(Te6edf3snapshot_dirTb4b4b4, Te6edf3filenameTb4b4b4)
Tff7b72if Tff7b72not Te6edf3full_path Tff7b72or Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3full_pathTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffSnapshot not foundTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff404Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffFileResponseTb4b4b4(
Te6edf3pathTff7b72=Te6edf3full_pathTb4b4b4,
Te6edf3headersTff7b72=Tb4b4b4{
Ta5d6ff"Ta5d6ffContent-DispositionTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff'Ta5d6ffattachment; filename=Ta5d6ff"Tffd700{Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffbasenameTb4b4b4(Te6edf3full_pathTb4b4b4)Tffd700}Ta5d6ff"Ta5d6ff'Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/database/healthTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffdatabase_healthTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffdatabaseTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffget_database_health_snapshotTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffFailed to fetch database health: Tffd700{Te6edf3eTffd700!s}Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/database/vacuumTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffdatabase_vacuumTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3result Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffrun_database_vacuumTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffDatabase vacuum completedTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffdatabaseTa5d6ff"Tb4b4b4: Te6edf3resultTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffFailed to vacuum database: Tffd700{Te6edf3eTffd700!s}Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/database/recoverTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffdatabase_recoverTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3result Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffrun_database_recoveryTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffDatabase recovery routine completedTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffdatabaseTa5d6ff"Tb4b4b4: Te6edf3resultTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffFailed to recover database: Tffd700{Te6edf3eTffd700!s}Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/database/backupTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffdatabase_backupTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3result Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffbackup_databaseTb4b4b4(Te6edf3appTff7b72.Td2a8ffstorage_pathTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffDatabase backup createdTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffbackupTa5d6ff"Tb4b4b4: Te6edf3resultTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffFailed to create database backup: Tffd700{Te6edf3eTffd700!s}Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/database/backup/downloadTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffdatabase_backup_downloadTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3backup_info Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffbackup_databaseTb4b4b4(Te6edf3appTff7b72.Td2a8ffstorage_pathTb4b4b4)
Te6edf3file_path Tff7b72= Te6edf3backup_infoTb4b4b4[Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4]
Tff7b72with Tffa657openTb4b4b4(Te6edf3file_pathTb4b4b4, Ta5d6ff"Ta5d6ffrbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3data Tff7b72= Te6edf3fTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffResponseTb4b4b4(
Te6edf3bodyTff7b72=Te6edf3dataTb4b4b4,
Te6edf3headersTff7b72=Tb4b4b4{
Ta5d6ff"Ta5d6ffContent-TypeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffapplication/zipTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffContent-DispositionTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff'Ta5d6ffattachment; filename=Ta5d6ff"Tffd700{Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffbasenameTb4b4b4(Te6edf3file_pathTb4b4b4)Tffd700}Ta5d6ff"Ta5d6ff'Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffFailed to create database backup: Tffd700{Te6edf3eTffd700!s}Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────